#ifndef _UNIQUE_PTR_HPP_
#define _UNIQUE_PTR_HPP_

#include <type_traits>
#include <utility>

namespace smt
{
// 默认析构器
template <class T>
struct default_delete
{
    constexpr default_delete() noexcept = default;

    void operator()(T* ptr) const
    {
        // 检查 T 是不是 void 类型
        static_assert(!std::is_void<T>::value, "void type");
        // 检查指针大小
        static_assert(sizeof(T) > 0, "error pointer");

        delete ptr;
    }
};

template <class T, class Deleter = default_delete<T>>
class unique_ptr
{
public:
    using pointer = T*;
    using element_type = T;
    using deleter_type = Deleter;

private:
    T* _p;
    Deleter _d;

public:
    // 删除拷贝构造
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

    // 默认构造
    constexpr unique_ptr() noexcept
    : _p(pointer()), _d(Deleter())
    {}

    // 空指针构造
    constexpr unique_ptr(std::nullptr_t) noexcept
    : _p(pointer()), _d(Deleter())
    {}

    // 裸指针构造
    explicit unique_ptr(pointer p) noexcept
    : _p(p), _d(Deleter())
    {}

    // 提供自定义删除器
    unique_ptr(pointer p, typename std::conditional<std::is_reference<deleter_type>::value,
    deleter_type, const deleter_type&>::type d) noexcept
    : _p(p), _d(d) {}

    // 移动构造函数
    unique_ptr(unique_ptr&& u) noexcept
    : _p(u.release()), _d(std::forward<deleter_type>(u.get_deleter())) {}

    // 移动构造函数(带自定义删除器)
    unique_ptr(pointer p, typename std::remove_reference<deleter_type>::type&& d) noexcept
    : _p(std::move(p)), _d(std::move(d))
    { static_assert(!std::is_reference<deleter_type>::value, "rvalue deleter bound to reference"); }

    // 移动赋值运算符
    unique_ptr& operator=(unique_ptr&& u) noexcept
    {
        reset(u.release());
        get_deleter() = std::forward<deleter_type>(u.get_deleter());
        return *this;
    }

    // 析构函数
    ~unique_ptr() noexcept
    {
        if (_p != nullptr)
            get_deleter()(_p);
        _p = pointer();
    }

    // 释放原来管理的指针
    pointer release() noexcept
    { 
        pointer old = get();
        _p = pointer();
        return old;
    }

    // 重设指针
    void reset(pointer ptr =  pointer()) noexcept
    {
        using std::swap;
        swap(_p, ptr);
        if (ptr != pointer())
            get_deleter()(ptr);
    }

    // 交换两个对象的指针
    void swap(unique_ptr& u) noexcept
    {
        using std::swap;
        swap(_p, u._p);
    }

    // 获取管理的指针
    pointer get() const noexcept
    { return _p; }

    // 获取删除器
    Deleter& get_deleter() noexcept
    { return _d; }

    const Deleter& get_deleter() const noexcept
    { return _d; }

    // bool 运算符重载
    explicit operator bool() const noexcept
    { return get() != nullptr; }

    // 提领运算符重载
    typename std::add_lvalue_reference<T>::type operator*() const
    noexcept(noexcept(*std::declval<pointer>()))
    { return *get(); }

    // 箭头运算符重载
    pointer operator->() const noexcept
    { return get(); }
};

}
#endif